#pragma once

#include <compl/candy.h>


/* ----------------------------------------------------------------
 * 一个基础的泛型函数库 */

/* ----------------------------------------------------------------
 * 数据结构相关 */
/* 转换数据结构 */
#define container_of(ptr, type, member) ({				\
	void *__mptr = (void *)(ptr);					\
	SASSERT_FAIL(IS_SAMETYPE(*(ptr), ((type *)0)->member) ||	\
			IS_SAMETYPE(*(ptr), void),			\
			"pointer type mismatch in container_of()");	\
	((type *)(__mptr - offsetof(type, member))); })

/* 转换数据类型 */
#define tcast(type, x)			(type)(x)

/* ----------------------------------------------------------------
 * 控制流相关 */
/* 获得当前返回地址、PC和栈指针 */
#define get_ret_ip()			((unsigned long)__builtin_extract_return_addr(__builtin_return_address(0)))
#define get_cur_ip()			({ __label__ __here; __here: (unsigned long)&&__here; })
#define get_frame_ptr(level)		(__builtin_frame_address(level))

/* ----------------------------------------------------------------
 * 对齐函数 */

/* 是否对齐 */
#define is_powerof2(x)			((((x)-1) & (x)) == 0)

/* 对对齐的使用LOG2 */
#define log2_align(x)			(fls_generic(x) - 1)

/* 这些只能2^n次方对齐使用 */
#define align_up(size, align)		((((align) - 1) | ((size) - 1)) + 1)
#define align_down(size, align)		((size) & (~((align) - 1)))

#define stksize_align(size)		((HDEF_STK_GROWS_DOWNWARD) ? align_down(size, HDEF_STK_ALIGN_BYTES) : \
					align_up(size, HDEF_STK_ALIGN_BYTES))

#define is_aligned(size, align) 	(!((size) & ((align) - 1)))
#define is_log2aligned(size, logn)	is_aligned(size, BIT(logn))

#define is_ptr_aligned(ptr, align)	is_aligned((size_t)ptr, align)
#define is_ptr_inbound(ptr, downbound, upbound)	(((paddr_t)(ptr) >= (paddr_t)(downbound)) && ((paddr_t)(ptr) <= (paddr_t)(upbound)))

#define pow2_rounddown(n, b) 		(((n) >> (b)) << (b))
#define pow2_roundup(n, b) 		(((((n) - 1UL) >> (b)) + 1UL) << (b))

SAI size_t __next_pow2(size_t sz) {
	sz |= sz >> 1;
	sz |= sz >> 2;
	sz |= sz >> 4;
	sz |= sz >> 8;
	sz |= sz >> 16;
	sz |= sz >> 32;
	return sz + 1;
}
/* FIXME: dangerous!!! */
#define next_pow2(x)			__next_pow2(x)
/* FIXME: 这个接口在clang编译会出错?? 是bug还是语义不同? */
#define next_pow2_bit(x)		(((x) == 1) ? 1 : __FLSG((x) - 1))
#define next_pow2_clz(x)		(1UL << (next_pow2_bit(x)))
/* ----------------------------------------------------------------
 * 比较大小相关 */
#define min(a,b) 			(((a)<(b))?(a):(b))
#define max(a,b) 			(((a)>(b))?(a):(b))

/* ----------------------------------------------------------------
 * 栈上内存申请 */
#define stkalloc(size)			(__builtin_alloca(size))
#define stkalloc_align(align, size)	(__builtin_alloca_with_align(size, align))

/* 清除核心cache */
#define clear_core_cache(sta, end)	__builtin___clear_cache(sta, end)

/* ----------------------------------------------------------------
 * 泛型哈希实现 */

/* 黄金分割数，用于哈希 */
#define GOLDEN_RATIO_8   		((uint8_t)0x61)
#define GOLDEN_RATIO_16   		((uint16_t)0x61C9)
#define GOLDEN_RATIO_32   		((uint32_t)0x61C88647)
#define GOLDEN_RATIO_64   		((uint64_t)0x61C8864680B583EBULL)

#define __GOLDEN_RATIO(word_bit)	GOLDEN_RATIO_##word_bit
#define _GOLDEN_RATIO(word_bit)		__GOLDEN_RATIO(word_bit)
#define GOLDEN_RATIO			_GOLDEN_RATIO(WORD_WIDTH)

/* 泛型哈希 */
#define __hash64(x)			((x) * GOLDEN_RATIO_64)
#define hash(x)				TIF_ELSE(sizeof(x) == sizeof(uint64_t), ((x) * GOLDEN_RATIO_64),\
	TIF_ELSE(sizeof(x) == sizeof(uint32_t), ((x) * GOLDEN_RATIO_32), 				\
		TIF_ELSE(sizeof(x) == sizeof(uint16_t), ((x) * GOLDEN_RATIO_16), 			\
			TIF_ELSE(sizeof(x) == sizeof(uint8_t), ((x) * GOLDEN_RATIO_8), 			\
			TCOND_UNREACHABLE)								\
			)										\
		)											\
	)

#define hash_2b(x, bits_bucket)		(hash(x) >> ((sizeof(x) * BYTE_WIDTH) - bits_bucket))
#define hash_mod(x, buckets)		(hash(x) % buckets)

/* TODO: 把泛型函数转换为特定函数的高阶宏函数 */
// #define cmpg(pa, pb)			\
// SASSERT((typeof(*pa) == typeof(*pb)) && (					\
// 	sizeof(*pa) == sizeof(uint128_t) || sizeof(*pa) == sizeof(uint64_t) ||	\
// 	sizeof(*pa) == sizeof(uint32_t) || sizeof(*pa) == sizeof(uint16_t) ||	\
// 	sizeof(*pa) == sizeof(uint8_t)));					\
// { (int)((*pa == *pb)?0:((*pa > *pb)?1:-1));  }

#define __CMP(a ,b)			{ (int)((*pa == *pb)?0:((*pa > *pb)?1:-1));  }
/* 定义泛型swap,首先是类型判断 */
#define __SWAP(type, a, b)		{ word_t __tmp = b; b = a; a = __tmp; }

SAI void generic_swap(void *a, void *b, size_t size){
	if (is_aligned(size, WORD_SIZE)){
		word_t *pa = (word_t *)a;
		word_t *pb = (word_t *)b;
		for (word_t i = 0; i < size / sizeof(word_t); i++){
			__SWAP(word_t, pa[i], pb[i]);
		}
	}else if(is_aligned(size, HWORD_SIZE)){
		hword_t *pa = (hword_t *)a;
		hword_t *pb = (hword_t *)b;
		for (word_t i = 0; i < size / sizeof(hword_t) ; i++){
			__SWAP(hword_t, pa[i], pb[i]);
		}
	}else{
		byte_t *pa = (byte_t *)a;
		byte_t *pb = (byte_t *)b;
		for (word_t i = 0; i < size / sizeof(byte_t) ; i++){
			__SWAP(byte_t, pa[i], pb[i]);
		}
	}

}

/* 数组knuth随机排序 */
SAI word_t shuffle_rand_gen(word_t seed, word_t cur_idx){
	return seed * (cur_idx + 1) * GOLDEN_RATIO;
}

#define shuffle(arr, n, rand_seed, cur_idx) do{								\
	for (sword_t i = n - 1; i > 0; i--){								\
		generic_swap(&((arr)[shuffle_rand_gen(rand_seed + i, cur_idx) % (i + 1)]), &((arr)[i]), sizeof((arr)[i]));\
	}												\
}while(0)

